#include <iostream>
#include <cstring>
#include <cerrno>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"
#include "Commen.hpp"

void usage(std::string proc_name)
{
    std::cout << "usage: \n\t" << proc_name << " ip port\n" << std::endl;
}

// ./udp_client 127.0.0.1 8080
int main(int argc, char* argv[])
{
    if(argc != 3)
    {
        usage(argv[0]);
        return 1;
    }

    std::string server_ip = argv[1];
    uint16_t server_port = std::stoi(argv[2]);

    // 1.创建socket
    int socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(socket_fd < 0)
    {
        log.message(FATAL, "socket error, %d: %s\n", errno, strerror(errno));
        return 2;
    }

    // 2.客户端不填本端网络信息，因为不做绑定

    // 3.客户端不显式绑定本端网络信息，udp cilent首次发送数据时，内核随机绑定
    // 用户机器上的端口使用情况，ip分配情况，只有内核知道，开发者不知道，不能明码绑定

    // 4.填写对端网络信息
    // 通信双方必须知道对方的网络信息，客户端明确知道目标主机是谁，初始化时就可以填写
    struct sockaddr_in server;
    bzero(&server, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(server_port);
    server.sin_addr.s_addr = inet_addr(server_ip.c_str()); //inet_addr将点分十进制ip转为四字节ip，并转为网络序列

    while(true)
    {
        std::string send_buffer;
        std::cout << ">> ";
        std::getline(std::cin, send_buffer);

        ssize_t send_n = sendto(socket_fd, send_buffer.c_str(), send_buffer.size(), 0, 
            (struct sockaddr*)&server, sizeof(server)); //网络信息server作输入输出型参数
        if(send_n > 0)
        {
            char recv_buffer[1024];
            struct sockaddr_in tmp;
            socklen_t len = sizeof(tmp);
            // tmp仅用于占位，recvfrom不建议添nullptr
            ssize_t recv_n = recvfrom(socket_fd, recv_buffer, sizeof(recv_buffer)-1, 0, (struct sockaddr*)&tmp, &len);
            if(recv_n > 0)
            {
                recv_buffer[recv_n] = '\0';
                std::cout << "echo: " << recv_buffer << std::endl;               
            }
        }
    }

    close(socket_fd);
    return 0;
}